﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Extensions.Logging;

using Newtonsoft.Json.Linq;

using Utils.Weixin.Pay.Http;
using Utils.Weixin.Pay.Options;
using Utils.Weixin.Pay.Result;

namespace Utils.Weixin.Pay
{
    public class WeChatPayForOpen : WeChatPay
    {
        private readonly WeChatPayOptions subOptions;

        public WeChatPayForOpen(WeChatPayOptions spOptions, WeChatPayOptions subOptions, ILogger<WeChatPayForOpen> logger, ICacheStrategy cacheStrategy)
            : base(spOptions, logger, cacheStrategy)
        {
            this.subOptions = subOptions;
        }


        public override async Task<string> CreatePayJsApi(string appId, string out_trade_no, decimal amount_total, string description, string openid = null, string attach = null, int valid_minute = 15)
        {
            if (string.IsNullOrEmpty(out_trade_no))
                throw new ArgumentException($"“{nameof(out_trade_no)}”不能为 null 或空。", nameof(out_trade_no));

            if (string.IsNullOrEmpty(description))
                throw new ArgumentException($"“{nameof(description)}”不能为 null 或空。", nameof(description));

            if (string.IsNullOrEmpty(subOptions.NotifyUrl))
                throw new ArgumentException($"“NotifyUrl”不能为 null 或空。", nameof(subOptions.NotifyUrl));
            if (openid.IsNullOrEmpty())
                throw Error.SystemError("缺少参数：openid");

            var json = await httpClient.PostAsync("v3/pay/partner/transactions/jsapi", new JsonContent(new
            {
                sp_appid = options.AppId,
                sp_mchid = options.MerchantNo,
                sub_appid = appId,
                sub_mchid = subOptions.MerchantNo,
                description = description.SubstringByte(0, 120),
                out_trade_no,
                amount = new
                {
                    total = (int)(amount_total * 100),
                    currency = "CNY"
                },
                payer = openid.IsNullOrEmpty() ? null : new
                {
                    sub_openid = openid
                },
                attach,
                notify_url = subOptions.NotifyUrl,
                time_expire = DateTime.Now.AddMinutes(valid_minute).ToString("yyyy-MM-ddTHH:mm:sszzz")
            })).ReadAsWxPayAsync<JObject>();
            return json["prepay_id"].ToString();
        }

        public override async Task<TransactionResult> QueryTransactions(string out_trade_no)
        {
            var obj = await httpClient.GetAsync($"v3/pay/partner/transactions/out-trade-no/{out_trade_no}?sp_mchid={options.MerchantNo}&sub_mchid={subOptions.MerchantNo}")
                   .ReadAsWxPayAsync<JObject>();
            return TransactionResult.Create(obj);
        }

        public override async Task<RefundResult> ApplyRefund(string out_trade_no, string out_refund_no, string reason, decimal refund, decimal total)
        {
            return await httpClient.PostAsync("v3/refund/domestic/refunds", new JsonContent(new
            {
                sub_mchid = subOptions.MerchantNo,
                out_trade_no,
                out_refund_no,
                reason,
                notify_url = subOptions.NotifyUrl,
                amount = new
                {
                    refund = (int)(refund * 100),
                    total = (int)(total * 100),
                    currency = "CNY"
                }
            }))
               .ReadAsWxPayAsync<RefundResult>();
        }

    }
}
